package com.itheima.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.dao.MenuDao;
import com.itheima.dao.PermissionDao;
import com.itheima.dao.RoleDao;
import com.itheima.dao.UserDao;
import com.itheima.entity.PageResult;
import com.itheima.pojo.Menu;
import com.itheima.pojo.Permission;
import com.itheima.pojo.Role;
import com.itheima.pojo.User;
import com.itheima.service.UserService;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户服务
 */
@Service(interfaceClass = UserService.class)
@Transactional
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Autowired
    private RoleDao roleDao;
    @Autowired
    private PermissionDao permissionDao;
    @Autowired
    private MenuDao menuDao;
    //根据用户名查询数据库获取用户信息和关联的角色信息，同时需要查询角色关联的权限信息
    @Override
    public User findByUsername(String username) {
        User user = userDao.findByUsername(username);//查询用户基本信息，不包含用户的角色
        if (user==null) {
            return null;//sc接受到null表示验证失败
        }
        Integer userId = user.getId();
        //根据用户的id去中间表中获取当前用户的所有的角色
        Set<Role> roles = roleDao.findByUserId(userId);
        //遍历所有的角色获取相应的权限
        for (Role role : roles) {
            Integer roleId = role.getId();
            //根据角色id拆线呢对应的权限
            Set<Permission> permissions = permissionDao.findByRoleId(roleId);
            //将权限集合放到对应的角色中
            role.setPermissions(permissions);
        }
        //将角色集合放到用户中
        user.setRoles(roles);
        return user;
    }
//查询管理用户的列表
    @Override
    public PageResult findUserList(Integer page, Integer limit) {
        //利用分页插件分页
        PageHelper.startPage(limit,page);
        //因为要用枫叶插件,所以必须返回Page类型
        Page<User> userPage=userDao.findUserList();
        return new PageResult(userPage.getTotal(),userPage.getResult());

    }
//新增后台管理用户
    @Override
    public void save(User user,Integer[] roleIds) {
        //保存用户
        userDao.save(user);
        //将用户id和角色id绑定
        //遍历
        Map<String,Integer> map =new HashMap<>();
        if (roleIds!=null&&roleIds.length>0) {
            for (Integer roleId : roleIds) {
                map.put("userID",user.getId());
                map.put("roleId",roleId);
                //添加关系
                userDao.saveRoleIdsByUserId(map);
            }
        }


    }
//跟新
    @Override
    public void updateById(User user,Integer[] roleIds) {
        //先删除中间表
        userDao.removeRoleByUserId(user.getId());
        //跟新中间表
        //将用户id和角色id绑定
        //遍历
        Map<String,Integer> map =new HashMap<>();
        if (roleIds!=null&&roleIds.length>0) {
            for (Integer roleId : roleIds) {
                map.put("userID",user.getId());
                map.put("roleId",roleId);
                //添加关系
                userDao.saveRoleIdsByUserId(map);
            }
        }
     userDao.updateById(user);
    }
//删除
    @Override
    public void removeById(int id) {
     //删除用户-角色中间表
        userDao.removeRoleByUserId(id);
        //删除用户表
        userDao.removeById(id);
    }
    //根据用户id获取对应的角色
    @Override
    public Map<String, Set<Role>> findRolesByUserId(int userId) {
        Map<String,Set<Role>> map=new HashMap<>();

        //获取当前用户所选的id
        Set<Role> existlist= roleDao.findByUserId(userId);
        map.put("existMap",existlist);
      //获取所有的角色id
        Set<Role> allRoles = roleDao.findAllRoles();
        map.put("allRoles",allRoles);
        return map;
    }

    @Override
    public User findUserById(Integer userId) {
      User user  =userDao.findUserById(userId);
        return user;
    }
//查询用户的菜单
    @Override
    public List<Menu> getMenuByUserAndRole(String username) {
        //根据用户名查询用户信息
        User user = userDao.findByUsername(username);
        //查询用户对应的角色信息
        Set<Role> rolesByUserId = roleDao.findByUserId(user.getId());
        //查询对应角色的页面(可能重复,用set过滤)
        //过滤所有重复的菜单id
         Set<Integer> menuIdsByUserId =new HashSet<>();
        for (Role role : rolesByUserId) {
            Set<Integer> menusByRoleId = menuDao.findMenusByRoleId(role.getId());
            menuIdsByUserId.addAll(menusByRoleId);
        }
        System.out.println("用户的菜单的id"+menuIdsByUserId);
        //将得到的user的菜单进行树形结果封装
        //查询对应用户的菜单信息
        List<Integer> ListmenuIdsByUserId=new ArrayList<>(menuIdsByUserId);
        System.out.println("用户的菜单的id,list="+menuIdsByUserId);
      List<Menu> menuList=menuDao.findMenuByMenuIds(ListmenuIdsByUserId);

        //封装数据
       List<Menu> resultMenuList= bulidTreeMenuByParentId(menuList);
        System.out.println("用户的菜单"+resultMenuList);
        return resultMenuList;
    }
     //封装数据 (通过子菜单封装树形菜单)
    public List<Menu> bulidTreeMenuByParentId(List<Menu> menuList) {
        //用来返回的list
        List<Menu> finallyListMenu=new ArrayList<>();


        //遍历用户的菜单将相同父id菜单对象封装到map中(父id,list<菜单对象>)
        Map<Integer,List<Menu>> mapByParentId=new HashMap<>();
        for (Menu menu : menuList) {
            //判断是否有父id
            if (menu.getParentMenuId()!=null) {
                //取菜单的id与map中的key比较,如果相等,就将菜单对像加到map的value中
                //获取map中的key的值
                Set<Integer> mapByParentIdWithKey = mapByParentId.keySet();
                if (mapByParentIdWithKey!=null && mapByParentIdWithKey.size()>0) {
                    //遍历map的key查询菜单中是否有父id等于key的
                    for (Integer key : mapByParentIdWithKey) {
                        if (menu.getParentMenuId()==key) {
                            //菜单的pid等于key表明他们在同一个父菜单下,将他们先放到此map的value中
                            //首先获取此key中的value
                            List<Menu> listMenuByPidInMapkey = mapByParentId.get(key);
                            //将对象加到value中
                            listMenuByPidInMapkey.add(menu);
                            //将新的value添加到此map的对应的key的value中
                            mapByParentId.put(key,listMenuByPidInMapkey);
                        }else{
                            //遍历完整个map的key发现没有对应的key,表明此map中没有,就创建
                            //得到此菜单的pid,将它作为map的key,菜单对象加入list集合
                            List<Menu> menuListBynewWithNotInMap=new ArrayList<>();
                            menuListBynewWithNotInMap.add(menu);
                            mapByParentId.put(menu.getParentMenuId(),menuListBynewWithNotInMap);
                        }
                    }
                }else{
                    //遍历完整个map的key发现没有对应的key,表明此map中没有,就创建
                    //得到此菜单的pid,将它作为map的key,菜单对象加入list集合
                    List<Menu> menuListBynewWithNotInMap=new ArrayList<>();
                    menuListBynewWithNotInMap.add(menu);
                    mapByParentId.put(menu.getParentMenuId(),menuListBynewWithNotInMap);
                }

            }else{

                finallyListMenu.add(menu);


              /*  //没有父id表示此对象已经是顶级菜单了
                //取出此菜单的id,再到map中查找有没有key为此菜单id的,有就证明此菜单的子菜单是对应key的值
                Integer rootId = menu.getId();
                Menu rootMenu = menuDao.findMenuByMenuId(rootId);
                //看看这个集合中有没有root菜单的子菜单
                //遍历所有菜单,找到pid等于我root菜单的
                //创建一个list保存root菜单的子菜单
                List<Menu> listWithSaveRootSon=new ArrayList<>();
                for (Menu menu1 : menuList) {
                    //如果有pid等于rootId的就将它添加到一个list中,存到root的children中
                    Integer parentMenuIdWithFindsonMenu = menu1.getParentMenuId();
                    if (parentMenuIdWithFindsonMenu!=null &&parentMenuIdWithFindsonMenu==rootId) {
                        listWithSaveRootSon.add(menu1);
                    }

                }
                //遍历完后将子菜单添加到root菜单
                rootMenu.setChildren(listWithSaveRootSon);
                //将顶级菜单放到list中返回
                finallyListMenu.add(rootMenu);
*/

            }

        }

        //遍历完成,到这里map中已经全是以父id为key,子菜单的list为value的map了
        //需要将map中的key全部取出来,查询以此key为id的菜单是否还有父菜单
        //遍历key
        //创建一个对象保存接下来 查询到的父菜单的list集合
        List<Menu> listWithSaveParentMenu=new ArrayList<>();
        Set<Integer> keyWithFindParentMenu = mapByParentId.keySet();
        if (keyWithFindParentMenu.size()<=0) {
            return finallyListMenu;

        }
        for (Integer key : keyWithFindParentMenu) {
            //查询此key对应的菜单
           Menu menuParent= menuDao.findMenuByMenuId(key);
           //找到了对应的父菜单,此时就应该将,map中对应的key的value加到父菜单的chldren中
            menuParent.setChildren(mapByParentId.get(key));
            listWithSaveParentMenu.add(menuParent);
        }
         //此时就得到了所有父菜单的集合
        //需要再对这个list进行包装成tree
        //如果此list长度大于0,则证明还要封装
        //递归
        if (listWithSaveParentMenu.size()>0 && listWithSaveParentMenu!=null) {
           return this.bulidTreeMenuByParentId(listWithSaveParentMenu);
        }else {
            return   finallyListMenu;
        }
           //全部封装完成,返回list

    }


}
